# -*- encoding: utf-8 -*-
"""
========================================
@Time   ：2021/9/7 9:59
@Auther ：shutao
@File   ：QTM_encode.py
@IDE    ：PyCharm
@Github ：https://github.com/NameLacker
@Gitee  ：https://gitee.com/nameLacker
========================================
"""

import paddle
from paddle_quantum.circuit import UAnsatz
import numpy as np


def ground_state_coding():
    """
    量子基态编码
    """
    # 量子比特的数量等于经典信息的长度
    n = 4
    # 初始化电路
    basic_enc = UAnsatz(n)
    # x 是经典信息
    x = '1011'
    # 如果第 i 维经典信息是1，那么我们在对应的量子比特上作用一个 X 门
    for i in range(len(x)):
        if x[i] == '1':
            basic_enc.x(i)
    print(basic_enc)

    basis_quan_state = basic_enc.run_state_vector()
    print(basis_quan_state.numpy())

    # 内置的基态编码函数
    built_in_basis_enc = UAnsatz(n)
    # 经典信息 x 需要是 Tensor 的形式
    x = paddle.to_tensor([1, 0, 1, 1])
    built_in_basis_enc.basis_encoding(x)
    built_in_basis_enc_state = built_in_basis_enc.run_state_vector()
    print(built_in_basis_enc_state.numpy())


def amplitude_coding():
    """
    振幅编码
    """
    # 内置振幅编码函数
    # 量子比特的数目为2
    n = 2
    # 初始化电路
    built_in_amplitude_dec = UAnsatz(n)
    # paddle.Tensor 形式的经典信息 x
    x = paddle.to_tensor([0.5, 0.5, 0.5])
    state = built_in_amplitude_dec.amplitude_encoding(x, 'state_vector')
    print(state.numpy())


def angle_encoding():
    """
    角度编码
    """
    n = 3
    # 初始化电路
    angle_enc = UAnsatz(n)
    # x 是需要编码的经典信息
    x = paddle.to_tensor([np.pi, np.pi, np.pi], 'float64')
    # 加一层 Ry 旋转门
    for i in range(len(x)):
        angle_enc.ry(x[i], i)
    print(angle_enc)
    # 对应编码后的量子态
    angle_quan_state = angle_enc.run_state_vector()
    print([np.round(i, 2) for i in angle_quan_state.numpy()])

    # 内置角度编码函数
    # 量子比特的数目是3
    n = 3
    # 初始化电路
    built_in_angle_enc = UAnsatz(n)
    # x是需要编码的经典信息
    x = paddle.to_tensor([np.pi, np.pi, np.pi], 'float64')
    built_in_angle_enc.angle_encoding(x, "ry")
    state = built_in_angle_enc.run_state_vector()
    print([np.round(i, 2) for i in state.numpy()])


def IQP_encoding():
    """
    IQP编码
    """
    # 量子比特的数量
    n = 4
    # 初始化电路
    iqp_enc = UAnsatz(n)
    # x 是经典信息
    x = paddle.to_tensor([-1.45, 3, 2, -0.05], 'float64')
    # S 集合中的每一对量子比特对都要加上 RZZ 门
    S = [[0, 1], [1, 2], [2, 3]]
    r = 1

    for i in range(r):
        # 加上一层 Hadamard 门
        iqp_enc.superposition_layer()
        # 加上一层旋转门 Rz
        for j in range(n):
            iqp_enc.rz(x[j], j)
        # 加上 RZZ 门
        for k in S:
            iqp_enc.cnot(k)
            iqp_enc.rz(x[k[0]] * x[k[1]], k[1])
            iqp_enc.cnot(k)

    print(iqp_enc)

    # 内置 IQP 编码
    # 量子比特的数量是 6
    n = 4
    # 初始化电路
    built_in_iqp_enc = UAnsatz(n)
    # x 是经典信息
    x = paddle.to_tensor([-1.45, 3, 2, -0.05], 'float64')
    # S 集合中的每一对量子比特对都要加上 RZZ 门
    S = [[0, 1], [1, 2], [2, 3]]
    # r 是 U 重复的次数
    r = 1
    built_in_iqp_enc.iqp_encoding(x, r, S)
    built_in_iqp_enc_state = built_in_iqp_enc.run_state_vector()
    print([np.round(i, 5) for i in built_in_iqp_enc_state.numpy()])


if __name__ == '__main__':
    IQP_encoding()
